/*
 * RandomNumberGenerator.java
 *
 * Created on January 8, 2007, 4:19 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package net.sf.iSnake.core;


import java.util.*;

/**
 *
 * @author thelinuxmaniac
 * @TODO implement random number generation using "import java.security.SecureRandom"
 */
public class RandomNumberGenerator {
    
    private Integer[] entropyPool;
    private Integer entropyPoolSize;
    private Integer entropyPoolBytePointer;
    private Integer maxValue;
    private Integer minValue;
    private long lastInvocationTime;
    private static Random randomGenerator;
    
    
    /**
     * Initializes the Entropy pool with random numbers between minValue (inclusive) and maxValue (exclusive)
     * @param minValue Minimum value of entropy pool data (inclusive). Integer as this class features will also be used for scoring
     * @param maxValue Maximum value of entropy pool date (exclusive). Integer as this class features will also be used for scoring
     */
    public RandomNumberGenerator(Integer entropyPoolSize,Integer minValue,Integer maxValue) {
        /**
         * @TODO do error checking (eg:ensure entropyPoolSize != 0, ....)
         */
        lastInvocationTime = Calendar.getInstance().getTimeInMillis();  // Log the invocation time
        this.maxValue = maxValue;
        this.minValue = minValue;
        randomGenerator = new Random(lastInvocationTime);
        
        this.entropyPoolSize = entropyPoolSize;
        entropyPool = new Integer[entropyPoolSize];
        fillEntropyPool(new Integer(0),entropyPoolSize-1);
        this.entropyPoolBytePointer = -1;        // array index starts from 0
    }

    /**
     * Returns a random number between minValue (inclusive) and maxValue (exclusive)
     * @return Fetches Random number from the entropy pool
     */
    public Integer getRandomNumber()
    {
        entropyPoolBytePointer++;
        
        if(entropyPoolBytePointer == (entropyPoolSize))   {
            fillEntropyPool(0,entropyPoolSize-1);
            entropyPoolBytePointer = 0;
            return entropyPool[entropyPoolBytePointer];
        }
        /*
        if(entropyPoolBytePointer == entropyPoolSize/2) {
            fillEntropyPool(new Integer(0),entropyPoolSize/2);
            System.out.println("\nCopied new values from 0 to "+(entropyPoolSize/2));
            // Open a new thread to fill up the entropyPool from    0 to entropyPoolSize/2                  index
        }
        if(entropyPoolBytePointer == (entropyPoolSize)) {      // as array index starts from 0
            // Open a new thread to fill up the entropyPool from    entropyPoolSize/2 to entropyPoolSize    index
            entropyPoolBytePointer = 0;                         // Reset the byte pointer to starting
            fillEntropyPool(entropyPoolSize/2+1,entropyPoolSize-1);
            System.out.println("\nCopied new values from "+(entropyPoolSize/2+1)+" to "+(entropyPoolSize-1));
            entropyPoolBytePointer = 0;
        }
        */
        return entropyPool[entropyPoolBytePointer];
    }

    /**
     * Fill the entropy pool with random numbers starting from 'startIndex' upto 'endIndex' (both inclusive)
     * eg: if startIndex = 0 and endIndex = 63 then this method fills data from index 0 to 63 indexed members
     * @param startIndex starting index of the pool that is to be filled
     * @param endIndex end index of the pool that is to be filled
     */
    public void fillEntropyPool(Integer startIndex,Integer endIndex)
    {
//        randomGenerator = new Random(Calendar.getInstance().getTimeInMillis() - lastInvocationTime);
        randomGenerator = new Random(Calendar.getInstance().getTimeInMillis());
        lastInvocationTime = Calendar.getInstance().getTimeInMillis();  // Log the invocation time
        
        Integer size = endIndex - startIndex;
        Integer index = startIndex;
        Integer randomData = new Integer(0);
        while(index != (size+1))
        {
            randomData = minValue + new Integer((int) Math.abs(randomGenerator.nextDouble()*maxValue));
            if(randomData >=maxValue)
                randomData -= minValue;
            if (randomData >= minValue) {
                entropyPool[index] = randomData;
                index++;
            }
        }
    }
}